package com.apobates.forum.orize.spring;

import com.apobates.forum.orize.OrizeExecutor;
import com.apobates.forum.orize.OrizeExecutorFactory;
import com.apobates.forum.orize.core.*;
import org.apache.commons.lang3.tuple.ImmutablePair;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.Objects;

/**
 * 封装Spring HandlerInterceptorAdapter的相关调用
 * 需要在Spring配置文件中注入此类
 * @author xiaofanku@live.cn
 * @since 20210822
 */
public class OrizeAuthHelper extends OrizeAuthCommonHelper {
    private final OrizeExecutor executor;
    private final OrizeMemberQuery memberQuery;
    private final OrizeAuthIgnoreConfig ignoreConfig;

    /**
     * 实例化
     * @deprecated
     * @param loaderType 资源生成类型,可选:xml,json,anno
     * @param resoucePath 当loader时xml/json时的资源所在的位置,需要放到WEB-INF目录下
     * @param webInfPath WEB-INF的位置
     * @param memberQuery OrizeMemberQuery实现的实例
     */
    private OrizeAuthHelper(String loaderType, String resoucePath, String webInfPath, OrizeMemberQuery memberQuery){
        this.executor = OrizeExecutorFactory.classical(getLoader(loaderType, resoucePath, webInfPath));
        this.memberQuery = memberQuery;
        this.ignoreConfig = OrizeAuthIgnoreConfig.defaultInstance();
    }

    /**
     * 实例化
     * @deprecated
     * @param loaderType 资源生成类型,可选:xml,json,anno
     * @param resoucePath 当loader时xml/json时的资源所在的位置,需要放到WEB-INF目录下
     * @param webInfPath WEB-INF的位置
     * @param memberQuery OrizeMemberQuery实现的实例
     * @param ignoreConfig 配置不需要验证的请求
     */
    private OrizeAuthHelper(String loaderType, String resoucePath, String webInfPath, OrizeMemberQuery memberQuery, OrizeAuthIgnoreConfig ignoreConfig){
        //可以变更OrizeExecutor的实现
        this.executor = OrizeExecutorFactory.classical(getLoader(loaderType, resoucePath, webInfPath));
        this.memberQuery = memberQuery;
        this.ignoreConfig = ignoreConfig;
    }

    /**
     * 实例化
     * @param builder 构造器助手
     */
    private OrizeAuthHelper(Builder builder){
        this.executor = OrizeExecutorFactory.classical(getLoader(builder.loaderType, builder.resoucePath, builder.webInfPath));
        this.memberQuery = builder.memberQuery;
        this.ignoreConfig = builder.ignoreConfig;
    }

    @Override
    protected String getFilterClassName() {
        return "OrizeAuthSpringHelper";
    }

    @Override
    protected OrizeMemberQuery getMemberQuery() throws Exception {
        return this.memberQuery;
    }

    /**
     * 执行验证
     * @param memberRolePredicate 用户角色验证谓词表达式,
     *                            OrizeMemberRoleAnyContainsPredicate(单一角色匹配规则)
     *                            OrizeMemberRoleContainsAllPredicate(多个角色匹配规则)
     * @param request Http请求
     * @return
     */
    public ImmutablePair<Boolean, Map> verify(OrizeMemberRolePredicate memberRolePredicate, HttpServletRequest request){
        if(null != ignoreConfig && ignoreConfig.isCustomConfig()){
            return authentication(this.executor, memberRolePredicate, request, ignoreConfig);
        }
        return authentication(this.executor, memberRolePredicate, request);
    }

    /**
     * 返回默认的验证助手类构造器
     * @param loaderType 资源加载类型
     * @param sc 上下文
     * @return
     */
    public static Builder defaultInstance(String loaderType, ServletContext sc){
        Objects.requireNonNull(sc);
        return new Builder(loaderType, sc.getRealPath("/WEB-INF/"));
    }

    /**
     * 验证助手类构造器
     */
    public static class Builder{
        private String loaderType;
        private String resoucePath = null;
        private String webInfPath;
        private OrizeMemberQuery memberQuery = null;
        private OrizeAuthIgnoreConfig ignoreConfig = null;

        private Builder(String loaderType, String webInfPath){
            this.loaderType = loaderType;
            this.webInfPath = webInfPath;
            this.ignoreConfig = OrizeAuthIgnoreConfig.defaultInstance();
        }

        /**
         * 当loadType是非anno时需要设置资源的路径,anno时系统会生成无需设置
         * @param resoucePath 手动创建(非注解自动创建)的资源所在WEB-INF下的位置
         * @return
         */
        public Builder setNotAnnoResourcePath(String resoucePath){
            this.resoucePath = resoucePath;
            return this;
        }

        /**
         * 设置用户信息查询实现类
         * @param memberQuery
         * @return
         */
        public Builder setMemberQuery(OrizeMemberQuery memberQuery){
            this.memberQuery = memberQuery;
            return this;
        }

        /**
         * 设置请求忽略的配置参数
         * @param ignoreConfig
         * @return
         */
        public Builder setIgnoreConfig(OrizeAuthIgnoreConfig ignoreConfig){
            if(null != ignoreConfig) {
                this.ignoreConfig = ignoreConfig;
            }
            return this;
        }

        /**
         * 返回验证助手类
         * @return
         */
        public OrizeAuthHelper build(){
            return new OrizeAuthHelper(this);
        }
    }
}
